package edu.nwpu.zya.coreops.modules.resource.service.impl;

import com.alibaba.fastjson.JSONObject;
import edu.nwpu.zya.coreops.common.utils.Constant;
import edu.nwpu.zya.coreops.modules.alert.entity.RuleRdsRelationEntity;
import edu.nwpu.zya.coreops.modules.alert.service.RuleRdsRelationService;
import edu.nwpu.zya.coreops.modules.alert.service.RuleService;
import edu.nwpu.zya.coreops.modules.job.entity.JobRdsRelationEntity;
import edu.nwpu.zya.coreops.modules.job.entity.ScheduleJobEntity;
import edu.nwpu.zya.coreops.modules.job.service.JobRdsRelationService;
import edu.nwpu.zya.coreops.modules.job.service.ScheduleJobService;
import edu.nwpu.zya.coreops.modules.monitor.entity.MetricEntity;
import edu.nwpu.zya.coreops.modules.monitor.service.MetricService;
import edu.nwpu.zya.coreops.modules.resource.entity.RdsMetricRelationEntity;
import edu.nwpu.zya.coreops.modules.resource.service.RdsMetricRelationService;
import edu.nwpu.zya.coreops.modules.resource.vo.MetricVo;
import edu.nwpu.zya.coreops.modules.resource.vo.RdsVo;
import edu.nwpu.zya.coreops.modules.sys.entity.SysUserEntity;
import edu.nwpu.zya.coreops.modules.sys.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.nwpu.zya.coreops.common.utils.PageUtils;
import edu.nwpu.zya.coreops.common.utils.Query;

import edu.nwpu.zya.coreops.modules.resource.dao.RdsDao;
import edu.nwpu.zya.coreops.modules.resource.entity.RdsEntity;
import edu.nwpu.zya.coreops.modules.resource.service.RdsService;
import org.springframework.transaction.annotation.Transactional;


@Service("rdsService")
public class RdsServiceImpl extends ServiceImpl<RdsDao, RdsEntity> implements RdsService {
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private MetricService metricService;

    @Autowired
    private RdsMetricRelationService rdsMetricRelationService;

    @Autowired
    private RuleRdsRelationService ruleRdsRelationService;

    @Autowired
    private RuleService ruleService;

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    private JobRdsRelationService jobRdsRelationService;

    /**
     * 查询RDS列表
     * @param params
     * @return
     */
    @Override
    public PageUtils queryRdsVoPage(Map<String, Object> params) {
        String type = (String) params.get("type");
        String key = (String) params.get("key");

        QueryWrapper<RdsEntity> queryWrapper = new QueryWrapper<>();

        if(!StringUtils.isEmpty(type)&&!StringUtils.isEmpty(key)){
            if ("instanceId".equalsIgnoreCase(type)) {
                queryWrapper.eq("instance_id", key);
            } else if ("name".equalsIgnoreCase(type)) {
                queryWrapper.like("name", key);
            } else if ("area".equalsIgnoreCase(type)) {
                queryWrapper.like("area", key);
            }
        }

        // 根据用户id查询所属的RDS
        Long userId = (Long) params.get("userId");
        if(userId.intValue()!= Constant.SUPER_ADMIN){
            queryWrapper.eq("user_id",userId);
        }

        IPage<RdsEntity> page = this.page(
                new Query<RdsEntity>().getPage(params),
                queryWrapper
        );
        PageUtils pageUtils=new PageUtils(page);

        if(page.getSize()>0){
            List<RdsVo> rdsVos = page.getRecords().stream().map(item -> {
                RdsVo rdsVo = new RdsVo();
                BeanUtils.copyProperties(item, rdsVo);

                SysUserEntity userEntity = sysUserService.getById(userId);
                rdsVo.setUsername(userEntity.getUsername());
                return rdsVo;
            }).collect(Collectors.toList());
            pageUtils.setList(rdsVos);
        }

        return pageUtils;
    }

    /**
     * 添加RDS实例，并开启模拟任务
     * @param rdsEntity
     */
    @Transactional
    @Override
    public void saveRds(RdsEntity rdsEntity) {
        this.save(rdsEntity);

        // 保存ECS实例后，开启模拟Mock
        startRdsMockTask(rdsEntity);
    }

    private void startRdsMockTask(RdsEntity rdsEntity) {
        ScheduleJobEntity scheduleJobEntity = new ScheduleJobEntity();
        scheduleJobEntity.setStatus(rdsEntity.getStatus()== Constant.RunningStatus.RUNNING.getValue()?Constant.ScheduleStatus.NORMAL.getValue():Constant.ScheduleStatus.PAUSE.getValue());
        scheduleJobEntity.setBeanName("rdsMockTask");
        scheduleJobEntity.setCronExpression("0/15 * * * * ? ");

        JSONObject paramsJson = new JSONObject();
        paramsJson.put("instanceId",rdsEntity.getInstanceId());
        scheduleJobEntity.setParams(paramsJson.toJSONString());

        scheduleJobService.saveJob(scheduleJobEntity);

        // 保存job和ecs的关系
        JobRdsRelationEntity jobRdsRelationEntity = new JobRdsRelationEntity();
        jobRdsRelationEntity.setRdsId(rdsEntity.getId());
        jobRdsRelationEntity.setJobId(scheduleJobEntity.getJobId());
        jobRdsRelationService.save(jobRdsRelationEntity);
    }

    /**
     * 更新RDS实例，同时更新模拟Mock任务状态
     * @param rds
     */
    @Transactional
    @Override
    public void updateByRds(RdsEntity rds) {
        this.updateById(rds);

        // 更新定时任务状态
        updateRdsMockTask(rds);
    }


    private void updateRdsMockTask(RdsEntity rds) {
        JobRdsRelationEntity jobRdsRelationEntity = jobRdsRelationService.getOne(new QueryWrapper<JobRdsRelationEntity>().eq("rds_id", rds.getId()));
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.getById(jobRdsRelationEntity.getJobId());
        if(rds.getStatus()== Constant.RunningStatus.RUNNING.getValue()){
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.NORMAL.getValue());
        }else {
            scheduleJobEntity.setStatus(Constant.ScheduleStatus.PAUSE.getValue());
        }
        scheduleJobService.update(scheduleJobEntity);
    }


    /**
     * 删除RDS实例
     * @param ids
     */
    @Transactional
    @Override
    public void removeRdsByIds(List<Long> ids) {
        this.removeByIds(ids);
        ids.stream().forEach(id->{
            // 1.删除对指标的监控
            List<RdsMetricRelationEntity> relationEntities = rdsMetricRelationService.list(new QueryWrapper<RdsMetricRelationEntity>().eq("rds_id", id));
            rdsMetricRelationService.removeByIds(relationEntities.stream().map(item->{
                return item.getId();
            }).collect(Collectors.toList()));

            // 2.如果有告警规则，删除所有告警规则
            List<RuleRdsRelationEntity> ruleRdsRelationEntities = ruleRdsRelationService.list(new QueryWrapper<RuleRdsRelationEntity>().eq("rds_id", id));
            if(ruleRdsRelationEntities.size()>0){
                ruleRdsRelationEntities.stream().forEach(item->{
                    // 2.1删除关系
                    ruleRdsRelationService.removeById(item.getId());
                    // 2.2 删除rule
                    ruleService.removeById(item.getRuleId());
                });

                // 删除告警规则下的所有定时告警任务
                ruleService.deleteAlertTask(ruleRdsRelationEntities.stream().map(item->{
                    return item.getRuleId();
                }).collect(Collectors.toList()));
            }
        });
        // 删除模拟Mock定时任务
        deleteRdsMockTask(ids);
    }

    @Override
    public void deleteRdsMockTask(List<Long> ids) {
        // 删除RdsMockTask以及关系表
        for (Long id :
                ids) {
            List<JobRdsRelationEntity> relationEntities = jobRdsRelationService.list(new QueryWrapper<JobRdsRelationEntity>().eq("rds_id", id));
            jobRdsRelationService.removeByIds(relationEntities.stream().map(item->{
                return item.getId();
            }).collect(Collectors.toList()));

            List<Long> jobIdList = relationEntities.stream().map(item -> {
                return item.getJobId();
            }).collect(Collectors.toList());
            Long[] jobIds = jobIdList.toArray(new Long[0]);
            // 只有这个方法能删除定时任务
            scheduleJobService.deleteBatch(jobIds);
        }
    }


    @Override
    public PageUtils queryMetricVoPageByType(Map<String, Object> params) {
        Integer type = Integer.parseInt((String) params.get("type"));
        Long rdsId = Long.parseLong((String) params.get("rdsId"));

        IPage<MetricEntity> page = metricService.page(
                new Query<MetricEntity>().getPage(params),
                new QueryWrapper<MetricEntity>().eq("type", type)
        );
        PageUtils pageUtils = new PageUtils(page);
        List<MetricEntity> metricEntities = page.getRecords();
        if(metricEntities.size()>0){
            List<MetricVo> metricVoList = metricEntities.stream().map(metric -> {
                MetricVo metricVo = new MetricVo();
                BeanUtils.copyProperties(metric, metricVo);
                RdsMetricRelationEntity one = rdsMetricRelationService.getOne(new QueryWrapper<RdsMetricRelationEntity>().eq("rds_id", rdsId).eq("metric_id", metric.getId()));

                metricVo.setIsMonitored(one==null?false:true);
                return metricVo;
            }).collect(Collectors.toList());
            pageUtils.setList(metricVoList);
        }

        return pageUtils;

    }

    @Override
    public void addMetrics(Long rdsId, List<Long> metricIds) {
        List<RdsMetricRelationEntity> ecsMetricRelationEntities = metricIds.stream().map(id -> {
            RdsMetricRelationEntity relationEntity = new RdsMetricRelationEntity();
            relationEntity.setRdsId(rdsId);
            relationEntity.setMetricId(id);
            return relationEntity;
        }).collect(Collectors.toList());

        rdsMetricRelationService.saveBatch(ecsMetricRelationEntities);
    }

    @Override
    public void cancelMetrics(Long rdsId, List<Long> metricIds) {
        metricIds.stream().forEach(id->{
            rdsMetricRelationService.remove(new QueryWrapper<RdsMetricRelationEntity>().eq("rds_id",rdsId).eq("metric_id",id));
        });
    }

    @Override
    public List<RdsEntity> getRdsListByUserId(Long userId) {
        return this.baseMapper.getRdsListByUserId(userId);
    }

    @Override
    public RdsEntity getRdsByRuleId(Long ruleId) {
        return this.baseMapper.getRdsByRuleId(ruleId);
    }

    @Override
    public RdsEntity getRdsByInstanceId(String instanceId) {
        return this.baseMapper.getRdsByInstanceId(instanceId);
    }
}